package com.anji.plus.gaea.oss.ossbuilder.builders;

import com.anji.plus.gaea.oss.config.OSSMinioProperties;
import com.anji.plus.gaea.oss.config.OSSProperties;
import com.anji.plus.gaea.oss.exceptions.GaeaOSSException;
import com.anji.plus.gaea.oss.exceptions.GaeaOSSExceptionBuilder;
import com.anji.plus.gaea.oss.ossbuilder.GaeaOSSTemplate;
import io.minio.PutObjectOptions;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.List;

/**
 * 文件存储 使用minio服务器
 *
 * @Author: lide
 * @since 2022/3/22 14:16
 */
public class MinioClient implements GaeaOSSTemplate {

    private static Logger logger = LoggerFactory.getLogger(MinioClient.class);

    private io.minio.MinioClient minioClient;

    // 存储桶名称
    private String bucketName;
    // 允许的文件后缀 白名单
    private String fileTypeWhiteList;

    @Override
    public String getFileTypeWhiteList() {
        return fileTypeWhiteList;
    }

    @Override
    public void close() {
        if(minioClient!=null){
            logger.info("shutdown-oss-client");
        }
    }

    public MinioClient(OSSProperties ossProperties){
        this.fileTypeWhiteList = ossProperties.getFileTypeWhiteList();
        String url = ossProperties.getMinio().getUrl();
        int port = ossProperties.getMinio().getPort();
        String accessKey = ossProperties.getMinio().getAccessKey();
        String secretKey = ossProperties.getMinio().getSecretKey();
        this.bucketName = ossProperties.getMinio().getBucketName();
        try{
            this.minioClient = new io.minio.MinioClient(url, port, accessKey, secretKey);
            // 如存储桶不存在，创建之。
            boolean found = minioClient.bucketExists(this.bucketName);
            if (!found) {
                minioClient.makeBucket(this.bucketName);
            }
            logger.info("初始化文件存储，激活Minio分布式存储桶:{}", this.bucketName);
        }catch (Exception e){
            logger.error("初始化文件存储，激活Minio存储桶:{}失败:{}" ,this.bucketName, e);
        }
    }

    /**
     * 文件上传，输入参数为InputStream
     *
     * @param file
     * @return
     */
    @Override
    public String uploadFileByInputStream(MultipartFile file, String fileObjectName) throws GaeaOSSException {
        //判断文件后缀名是否在白名单中，如果不在报异常，中止文件保存
        checkFileSuffixName(file);

        InputStream fileInputStream = null;
        try {
            fileInputStream = file.getInputStream();
            PutObjectOptions options = new PutObjectOptions(fileInputStream.available(), -1);
            options.setContentType("application/octet-stream");
            minioClient.putObject(this.bucketName, fileObjectName, fileInputStream, options);
        } catch (Exception e) {
            logger.error("save file to minio store error:", e);
            throw GaeaOSSExceptionBuilder.build("save file to minio store error", e);
        } finally {
            try {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
            } catch (Exception e) {
                logger.error("close InputStream error:", e);
            }
        }
        return fileObjectName;
    }

    /**
     * 根据fileUUid下载文件
     *
     * @param fileObjectName
     * @return
     */
    @Override
    public byte[] downloadFile(String fileObjectName) throws GaeaOSSException {
        byte[] fileBytes = null;
        InputStream inputStream = null;
        try {
            inputStream = minioClient.getObject(this.bucketName, fileObjectName);
            if (inputStream == null) {
                logger.error("file {} not exist in minio store ", fileObjectName);
                throw GaeaOSSExceptionBuilder.build("file not exist in minio store, objectName="+ fileObjectName);
            }
            fileBytes = IOUtils.toByteArray(inputStream);
        } catch (Exception e) {
            logger.error("read file from minio store error:", e);
            throw GaeaOSSExceptionBuilder.build("read file from minio store error, objectName="+ fileObjectName);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (Exception e) {

                }
            }
        }
        return fileBytes;
    }

    @Override
    public void deleteFile(String fileObjectName) {
        try{
            minioClient.removeObject(this.bucketName, fileObjectName);
        }catch (Exception e){
            logger.warn("delete file in minio store fail, bucket={}, file={}", this.bucketName, fileObjectName);
        }
    }

    @Override
    public void deleteFiles(List<String> fileObjectNames) {
        try{
            if(CollectionUtils.isEmpty(fileObjectNames)){
                return;
            }
            minioClient.removeObjects(this.bucketName, fileObjectNames);
        }catch (Exception e){
            logger.warn("delete file in minio store fail, bucket={}, file={}", this.bucketName, fileObjectNames.toString());
        }
    }
}
